/*
 * DumpTruck.java
 *
 * Created on September 17, 2007, 9:20 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package dumptruck;

import java.util.ArrayList;
import java.util.Random;
import jsim.statistic.SampleStat;
import simulationengine.event.Entity;
import simulationengine.event.Event;
import simulationengine.event.Scheduler;

/**
 * This class simulates Dump trucks, which haul coal as described in example 3.5
 * @author Eric Drucker
 */
public class DumpTruck
{
	static Scheduler scheduler;
	
	static SampleStat systemStats; 
	static SampleStat loadingStats;
	static SampleStat weighingStats;
	static SampleStat travelStats;
	
	static int numBeingLoaded;
	static int numBeingWeighed;
	
	static ArrayList<Entity> loadingWaitQueue = new ArrayList<Entity>();
	static ArrayList<Entity> weighingWaitQueue = new ArrayList<Entity>();
	
	/** Creates a new instance of DumpTruck */
	public DumpTruck()
	{
		numBeingLoaded = 0;
		numBeingWeighed = 0;
	
		scheduler = new Scheduler();
		
		systemStats = new SampleStat("Time in system");
		loadingStats = new SampleStat("Time in loading dock");
		weighingStats = new SampleStat("Time in weighing area");
		travelStats = new SampleStat("Time in travel");
		
	}
	
	
	static class Arrival extends Event
	{
		Arrival(Entity truck, double time)
		{
			super(truck, time);
		}
		
		public void occur()
		{
			Random rand = new Random();
			
			systemStats.tally(scheduler.getSystemTime() - getEntity().getStartTime());
			
			getEntity().setStartTime(scheduler.getSystemTime());
			
			if(numBeingLoaded < 2)
			{
				numBeingLoaded++;
				
				double loadingTime = scheduler.getSystemTime();
				//schedule end loading event
				int randInt = rand.nextInt(100);
				if(randInt < 30)
					loadingTime += 5.0;
				else if(randInt < 80)
					loadingTime += 10.0;
				else if(randInt < 100)
					loadingTime += 15.0;
				loadingStats.tally(loadingTime - scheduler.getSystemTime());
				
				scheduler.schedule(new LoadingCompletion(getEntity(), loadingTime));
			}
			else
			{
				//loading dock is full, wait in queue for dock to become free
				loadingWaitQueue.add(getEntity());
			}
		}
	}
	
	static class LoadingCompletion extends Event
	{
		LoadingCompletion(Entity truck, double time)
		{
			super(truck, time);
		}
		
		public void occur()
		{
			Random rand = new Random();
			int randInt;
			
			//loading is done, allow next person to load
			numBeingLoaded--;
			if(loadingWaitQueue.size() > 0)
			{
				numBeingLoaded++;
					
				double loadingTime = scheduler.getSystemTime();
				Entity nextEntity = loadingWaitQueue.remove(0);
				randInt = rand.nextInt(100);
				if(randInt < 30)
					loadingTime += 5.0;
				else if(randInt < 80)
					loadingTime += 10.0;
				else if(randInt < 100)
					loadingTime += 15.0;
				loadingStats.tally(loadingTime - scheduler.getSystemTime());
				
				scheduler.schedule(new LoadingCompletion(nextEntity, loadingTime));
			}
			
			if(numBeingWeighed < 1)
			{
				numBeingWeighed++;
				
				double weighingTime = scheduler.getSystemTime();
				//schedule end weighing event
				randInt = rand.nextInt(100);
				if(randInt < 70)
					weighingTime += 12.0;
				else if(randInt < 100)
					weighingTime += 16.0;
				weighingStats.tally(weighingTime - scheduler.getSystemTime());
				
				scheduler.schedule(new WeighingCompletion(getEntity(), weighingTime));
			}
			else
			{
				//weighing area is full, wait in queue for area to become free
				weighingWaitQueue.add(getEntity());
			}
			
		}
	}
	
	
	static class WeighingCompletion extends Event
	{
		WeighingCompletion(Entity truck, double time)
		{
			super(truck, time);
		}
		
		public void occur()
		{
			Random rand = new Random();
			int randInt;
			
			//weighing is done, allow next person to weigh
			numBeingWeighed--;
			if(weighingWaitQueue.size() > 0)
			{
				numBeingWeighed++;
				
				double weighingTime = scheduler.getSystemTime();
				Entity nextEntity = weighingWaitQueue.remove(0);
				randInt = rand.nextInt(100);
				if(randInt < 70)
					weighingTime += 12.0;
				else if(randInt < 100)
					weighingTime += 16.0;
				weighingStats.tally(weighingTime - scheduler.getSystemTime());
				
				scheduler.schedule(new WeighingCompletion(nextEntity, weighingTime));
			}
			
			double travelTime = scheduler.getSystemTime();
			//schedule arrival event
			randInt = rand.nextInt(100);
			if(randInt < 40)
				travelTime += 40.0;
			else if(randInt < 70)
				travelTime += 60.0;
			else if(randInt < 90)
				travelTime += 80.0;
			else if(randInt < 100)
				travelTime += 100.0;
			travelStats.tally(travelTime - scheduler.getSystemTime());
			
			scheduler.schedule(new Arrival(getEntity(), travelTime));
		}
	}
	
    /**
     * This method starts the simulation and continues until finished
     */
	public static void run()
	{
		
		//create initial states
		Entity truck1 = new Entity();
		truck1.setStartTime(0.0);
		Entity truck2 = new Entity();
		truck2.setStartTime(0.0);
		Entity truck3 = new Entity();
		truck3.setStartTime(0.0);
		Entity truck4 = new Entity();
		truck4.setStartTime(0.0);
		Entity truck5 = new Entity();
		truck5.setStartTime(0.0);
		Entity truck6 = new Entity();
		truck6.setStartTime(0.0);
		
		numBeingLoaded = 2;
		scheduler.schedule(new LoadingCompletion(truck1, 0.0));
		scheduler.schedule(new LoadingCompletion(truck2, 0.0));
		
		loadingWaitQueue.add(truck3);
		loadingWaitQueue.add(truck4);
		loadingWaitQueue.add(truck5);
		loadingWaitQueue.add(truck6);
		
		
		while(scheduler.getSystemTime() < 10000.0)
		{
			scheduler.handle();
		}
		
		systemStats.printStat();
		sleep();
		loadingStats.printStat();
		sleep();
		weighingStats.printStat();
		sleep();
		travelStats.printStat();
	}
	
	private static void sleep()
	{
		for (int i = 0; i < 10000; i++)
		{
			for(int j = 0; j < 10000; j++)
			{
				j = j;
			}
		}
	}
	
    /**
     * Creates a new DumpTruck simulation and begins
     */
	public static void main(String args[])
	{
		DumpTruck dt = new DumpTruck();
		dt.run();
	}
	
	//tally accumulate j
}
